#include "lagrange.h"
#include "math.h"
#include "stdio.h"

Lagrange::Lagrange(int error, double x_cotainferior, double x_cotasuperior, double y_cotainferior, double y_cotasuperior)
{
    this->_chebychev = new Chebychev(error);
    this->x_cotainferior=x_cotainferior;
    this->x_cotasuperior=x_cotasuperior;
    this->y_cotainferior=y_cotainferior;
    this->y_cotasuperior=y_cotasuperior;
    this->error = error;
}

Lagrange::~Lagrange()
{
    delete this->_chebychev;
}

double Lagrange::calcular(QString nombreFuncion, double num)
{

    int n=this->_chebychev->cantidadNodos;
    double ys[n];

    for(int k=0;k<n;k++)
    {
        double nodo=this->_chebychev->nodos[k];
        double valor;
        if(nombreFuncion.compare("seno")==0)
            valor=sin(nodo);
        if(nombreFuncion.compare("coseno")==0)
            valor=cos(nodo);
        ys[k]= valor;
    }
    return this->evaluar(num, (double*)&ys);
}

void Lagrange::pintarFuncion(MyCanvas* canvas, QString nombreFuncion)
{
    QPainter painter(canvas);
    painter.setPen(Qt::blue);
    QSize* size = &canvas->size();
    for(int i=1;i<size->width();i++)
    {
        double x1=this->x_funcion(i-1, size);
        //qDebug("%f", x1);
        double x2=this->x_funcion(i,size);

        double y1=this->calcularTrigonometrica(nombreFuncion, x1);
        double y2=this->calcularTrigonometrica(nombreFuncion, x2);

        int nx1=this->x_canvas(x1, size);
        int ny1=this->y_canvas(y1, size);
        int nx2=this->x_canvas(x2, size);
        int ny2=this->y_canvas(y2, size);

        painter.drawLine(nx1,ny1, nx2,ny2);
    }
}

double Lagrange::evaluar(double x, double *ys)
{
    int n = this->_chebychev->cantidadNodos;

    double sumatoria = 0.0;

    for(int k=0;k<n;k++)
    {
        double yk=ys[k];
        double xk=this->_chebychev->nodos[k];
        double prod=1.0;

        for(int i=0;i<n;i++)
        {
            if (k != i)
            {
                double xi=this->_chebychev->nodos[i];
                prod=prod* (x - xi)/(xk - xi);
            }
        }
        sumatoria += yk*prod;
    }
    return sumatoria;
}


int Lagrange::x_canvas(double coordenada, QSize* size)
{
    double nuevox=this->cambiarSistemaCoordenadas(coordenada, this->x_cotainferior, this->x_cotasuperior, 0, size->width());
    //return (int)nuevox+size->width()/2;
    return (int)nuevox;
}

int Lagrange::y_canvas(double coordenada, QSize* size)
{
    double nuevoy=this->cambiarSistemaCoordenadas(coordenada, this->y_cotainferior, this->y_cotasuperior, size->height(), 0);
    //return (int)-nuevoy+size->height()/2;
    return (int)nuevoy;
}


double Lagrange::x_funcion(int coordenada, QSize* size)
{
    //coordenada=coordenada-size->width()/2;
    double x=this->cambiarSistemaCoordenadas(coordenada,0, size->width(), this->x_cotainferior, this->x_cotasuperior);
    return x;
}

double Lagrange::y_funcion(int coordenada, QSize* size)
{
    //coordenada=-coordenada+size->height()/2;
    double y=this->cambiarSistemaCoordenadas(coordenada,size->width(), 0, this->x_cotainferior, this->x_cotasuperior);
    return y;
}

double Lagrange::calcularTrigonometrica(QString nombreFuncion, double angulo)
{
    double multiplicador=1;
    if(nombreFuncion.compare("seno")==0 && angulo<0)
    {
        multiplicador=-1;
        angulo=-angulo;

    }
    if(nombreFuncion.compare("coseno")==0 && angulo<0)
    {
        angulo=-angulo;
    }
    int cuadrante = ((int)(angulo/(PI/2))) % 4;
    double resultado, modulo;
    resultado=0;
    modulo=fmod(angulo,(PI/2.0));
    switch (cuadrante){
    case 0:
        if (nombreFuncion.compare("seno")==0){
            resultado= calcular("seno",modulo)*multiplicador;
        }else
        {
            resultado= calcular("coseno",modulo);
        }
        break;
    case 1:
        if (nombreFuncion.compare(QString("seno"))==0){
            resultado= calcular("seno",(PI/2.0) - modulo)*multiplicador;
        }else
        {
            resultado= - calcular("coseno",(PI/2.0) - modulo);
        }
       break;
    case 2:
        if (nombreFuncion.compare("seno")==0){
            resultado= - calcular("seno",modulo)*multiplicador;
        }else
        {
            resultado= - calcular("coseno",modulo);
        }
       break;
    case 3:
        if (nombreFuncion.compare("seno")==0){
            resultado= - calcular("seno",(PI/2.0) - modulo)*multiplicador;
        }else
        {
            resultado= calcular("coseno",(PI/2.0) - modulo);
        }
       break;
    }
    return resultado;
}

double Lagrange::cambiarSistemaCoordenadas(double coordenada, double cotainferiorvieja, double cotasuperiorvieja, double cotainferiornueva, double cotasuperiornueva)
{
    double a=cotainferiorvieja;
    double b=cotasuperiorvieja;
    double ap=cotainferiornueva;
    double bp=cotasuperiornueva;
    double resultado=ap+(coordenada-a)*(bp-ap)/(b-a);
    return resultado;

}
